package com.sinodata.bsm.cicp.collector.common;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.cicp.util.CommandReader;
import com.sinodata.bsm.common.vo.ResPropertyValue;

/**
 * 
 * <p>
 * Description:主机连接的采集器，通过Ping的方式采集。
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-12-20 15:29:33      liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class HostConnectCollector extends Collector {

    private static final Logger logger = Logger.getLogger(HostConnectCollector.class);

    private final PingSupport support = null;

    private static final int count = 5;

    public HostConnectCollector() {

    }

    @Override
    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        String newIp = this.paramMap.get("hostIP");
        if (newIp != null && newIp.trim().length() > 0) {
            ip = newIp;
        }
        int sendPkg = 0;
        int recvPkg = 0;
        for (int i = 0; i < 2; i++) {
            sendPkg += count;
            try {
                recvPkg += ping(ip, count);
            } catch (Exception e) {
                logger.error("failed to Ping", e);
                throw new CollectorException(e);
            }
            if (recvPkg != 0) {
                break;
            }
        }
        List values = new ArrayList();
        ResPropertyValue propertyValueX = new ResPropertyValue();
        ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[3];
        String[] propMetas = this.getPropMeta();
        propValues[0] = ResPropertyValue.createPropValue(String.valueOf(sendPkg), propMetas[0]);
        propValues[1] = ResPropertyValue.createPropValue(String.valueOf(recvPkg), propMetas[1]);
        propValues[2] = ResPropertyValue.createPropValue(String.valueOf(((double) (sendPkg - recvPkg) / sendPkg) * 100), propMetas[2]);
        propertyValueX.setValues(propValues);
        values.add(propertyValueX);
        return values;
    }

    @Override
    public String[] getParamMeta() {
        return new String[] { "hostIP" };
    }

    @Override
    public String[] getPropMeta() {
        return new String[] { "sendPacks", "receivePacks", "lostPackRate" };
    }

    /**
     * 
     * @param host
     * @param count
     * @return
     */
    public int ping(String host, int pkgCount) throws Exception {
        PingSupport ping = getPingSupport();
        //LinuxPingSupport ping = new LinuxPingSupport();//该
        if (ping == null) {
            throw new Exception("Without the support of the ping of this platform");
        }
        // PatternMatcher matcher = new Perl5Matcher();
        Matcher matcher = null;
        BufferedReader reader = null;
        try {
            //reader = CollectorUtil.getLocalReader(ping.getCommand(host, pkgCount));//reader = null
            reader = CommandReader.getLocalReader(ping.getCommand(host, pkgCount), 0, 0);
            //reader = CommandReader.getReader(host, ping.getCommand(host, pkgCount), 0, 0);
            String line = null;
            while ((line = reader.readLine()) != null) {
                matcher = ping.getMatchPattern().matcher(line);
                /* if (matcher.matches(line, ping.getMatchPattern())) {
                     MatchResult match = matcher.getMatch();
                     int sendPkg = Integer.parseInt(match.group(1).trim());
                     if (sendPkg == pkgCount) {
                         return Integer.parseInt(match.group(2).trim());
                     }
                 }*/
                if (matcher.find()) {
                    int sendPkg = Integer.parseInt(matcher.group(1).trim());
                    if (sendPkg == pkgCount) {
                        return Integer.parseInt(matcher.group(2).trim());
                    }
                }
            }
            throw new Exception("failed to Ping,return result format error");
        } catch (Exception ex) {
            logger.error("failed to Ping", ex);
            throw new CollectorException(ex);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    logger.error("failed to close BufferedReader", e);
                }
            }
        }
    }

    private PingSupport getPingSupport() {
        if (support == null) {
            String os = System.getProperties().getProperty("os.name");
            if (os.indexOf("Windows") != -1) {
                return new WindowsPingSupport();
            } else if (os.indexOf("Linux") != -1) {
                return new LinuxPingSupport();
            } else if (os.indexOf("AIX") != -1) {
                return new AixPingSupport();
            } else if (os.indexOf("SunOS") != -1) {
                return new SorialsPingSupport();
            } else if (os.indexOf("HP-UX") != -1) {
                return new HpPingSupport();
            }
        }
        return support;
    }

    abstract class PingSupport {
        private Pattern pattern = null;

        abstract String getCommand(String ip, int pkgCount);

        abstract String getPatternString();

        Pattern getMatchPattern() {
            if (pattern == null) {
                synchronized (this) {
                    if (pattern == null) {
                        // PatternCompiler compiler = new Perl5Compiler();
                        try {
                            // pattern = compiler.compile(getPatternString());
                            pattern = Pattern.compile(getPatternString());
                        } catch (Exception e) {

                        }
                    }
                }
            }
            return pattern;
        }
    }

    class WindowsPingSupport extends PingSupport {

        @Override
        public String getCommand(String ip, int pkgCount) {
            return "ping -n " + pkgCount + " " + ip;
        }

        @Override
        public String getPatternString() {
            return ".*=\\s+(\\d+).*=\\s+(\\d+).*=\\s+\\d+\\s+\\((\\d+)%.*";
            //            return "\\s+Packets:\\s+Sent\\s+=\\s+(\\d+),\\sReceived\\s+=\\s+(\\d+),\\s+Lost\\s+=\\s+\\d+\\s+\\((\\d+)%.*";
        }
    }

    class AixPingSupport extends PingSupport {

        @Override
        public String getCommand(String ip, int pkgCount) {
            return "ping -c " + pkgCount + " " + ip;
        }

        @Override
        public String getPatternString() {
            return "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";
        }
    }

    class LinuxPingSupport extends PingSupport {

        @Override
        public String getCommand(String ip, int pkgCount) {
            return "ping -c " + pkgCount + " " + ip;
        }

        @Override
        public String getPatternString() {
            return "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+received.*,\\s+(\\d+)%.*";
        }
    }

    class HpPingSupport extends PingSupport {

        @Override
        public String getCommand(String ip, int pkgCount) {
            return "ping " + ip + " -n " + pkgCount;
        }

        @Override
        public String getPatternString() {
            return "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";
        }
    }

    class SorialsPingSupport extends PingSupport {

        @Override
        public String getCommand(String ip, int pkgCount) {
            return "ping -s " + ip + " 56 " + pkgCount;
        }

        @Override
        public String getPatternString() {
            return "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

    }

}
